package sat.component;

import gov.pnnl.components.visibleComponents.widgets.radialMenu.MTRadialMenu;
import gov.pnnl.components.visibleComponents.widgets.radialMenu.item.MTMenuItem;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.mt4j.MTApplication;
import org.mt4j.components.TransformSpace;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.components.visibleComponents.shapes.MTRoundRectangle;
import org.mt4j.input.IMTInputEventListener;
import org.mt4j.input.gestureAction.TapAndHoldVisualizer;
import org.mt4j.input.inputData.MTFingerInputEvt;
import org.mt4j.input.inputData.MTInputEvent;
import org.mt4j.input.inputProcessors.IGestureEventListener;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapAndHoldProcessor.TapAndHoldEvent;
import org.mt4j.input.inputProcessors.componentProcessors.tapAndHoldProcessor.TapAndHoldProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapProcessor;
import org.mt4j.util.MTColor;
import org.mt4j.util.math.Vector3D;
import org.mt4jx.components.visibleComponents.widgets.toolbar.MTLayoutContainer;

import sat.frame.WorkPlaceScene;

public class Toolbar extends MTRoundRectangle implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private MTApplication app;

	private MTLayoutContainer classIconContainer;
	private MTLayoutContainer useCaseIconContainer;
	private MTLayoutContainer diagramIconContainer;
	private MTLayoutContainer currentContainer; 
	private boolean isOpened = true;

	private Toolbar instance;

	private ToolbarTabArray tabList;

	private boolean tappable = true;

	static final float cornerRadius = 20;
	static final float toolBarHeight = 85;
	static final float minTbWidth = 400;
	static float toolBarWidth = minTbWidth;
	static final float touchableSpaceWidth = 150;
	static final float tabListWidth = 300;
	public static final float tabListHeight = 35;

	public ToolbarTabArray getTabArray(){
		return tabList;
	}

	public void hide(){
		isOpened = false;
		currentContainer.setVisible(false);
		tabList.setVisible(false);
		this.setSizeLocal(cornerRadius*2, cornerRadius*2);
	}

	public void show(){
		isOpened = true;
		currentContainer.setVisible(true);
		tabList.setVisible(true);

		/*
		 * We suppose that classIconContainer has the longest width,
		 * so its width is used here to calculate the width of the tool bar
		 * 
		 * It will be better, if we use the scrolling list view -> TODO
		 */

		this.setSizeLocal(toolBarWidth, toolBarHeight);
	}

	public void changeCurrentContainer(MTLayoutContainer newContainer){
		if(!newContainer.isVisible()){ // only the invisible container will be refreshed, thus, we can improve efficiency
			currentContainer.setVisible(false);
			currentContainer = newContainer;
			currentContainer.setVisible(true);
			currentContainer.setPositionRelativeToParent(getCenterPointLocal());

			toolBarWidth = currentContainer.getWidthXY(TransformSpace.GLOBAL)+touchableSpaceWidth;
			toolBarWidth =  toolBarWidth > minTbWidth ? toolBarWidth : minTbWidth; //min Width
			this.setSizeLocal(toolBarWidth, toolBarHeight);
		}
	}

	// Constructor
	public Toolbar(final MTApplication mtApplication, WorkPlaceScene workPlaceScene){
		super(mtApplication,
				0,								// x
				0,   							// y
				0, 								// z
				0, 							 	// width
				toolBarHeight, 						// height
				cornerRadius, 					// arc width
				cornerRadius); 					// arc height

		this.setFillColor(new MTColor(122, 142, 117, 255));
		this.setStrokeColor(new MTColor(164, 117, 91, 255));
		this.setStrokeWeight(3);
		app = mtApplication;
		instance = this;

		//path to image files
		String imagePath = System.getProperty("user.dir") + File.separator + "icons" + File.separator;

		/*
		 * UML CLASS 
		 */

		//create one MTLayoutContainer for the main icons		
		classIconContainer = new MTLayoutContainer(MTLayoutContainer.ALIGN_BOTTOM, MTLayoutContainer.LAYOUT_HORIZONTAL, app);

		// add the icons with the same size 
		final ToolbarIcon classIcon = new ToolbarIcon(app.loadImage(imagePath+"class.png"), app,workPlaceScene);
		classIcon.setName("class");
		final ToolbarIcon intfaceIcon = new ToolbarIcon(app.loadImage(imagePath+"interface.png"), app,workPlaceScene);
		intfaceIcon.setName("interface");

		/* Must set Alignment and Layout before addChild.
		 * Because it's the addChild() function valid the alignment and the Layout
		 */
		classIconContainer.addChild(classIcon);
		classIconContainer.addChild(intfaceIcon);
		classIconContainer.setNoStroke(true);

		/*
		 * UML USE CASE 
		 */

		//create one MTLayoutContainer for the main icons		
		useCaseIconContainer = new MTLayoutContainer(MTLayoutContainer.ALIGN_BOTTOM, MTLayoutContainer.LAYOUT_HORIZONTAL, app);

		// add the icons with the same size 
		final ToolbarIcon peopleIcon = new ToolbarIcon(app.loadImage(imagePath+"people.png"), app,workPlaceScene);
		peopleIcon.setName("people");
		final ToolbarIcon associationIcon = new ToolbarIcon(app.loadImage(imagePath+"oval.png"), app,workPlaceScene);
		associationIcon.setName("association");

		/* Must set Alignment and Layout before addChild.
		 * Because it's the addChild() function valid the alignment and the Layout
		 */
		useCaseIconContainer.addChild(peopleIcon);
		useCaseIconContainer.addChild(associationIcon);
		useCaseIconContainer.setNoStroke(true);

		/*
		 * Diagram 
		 */

		//create one MTLayoutContainer for the main icons		
		diagramIconContainer = new MTLayoutContainer(MTLayoutContainer.ALIGN_BOTTOM, MTLayoutContainer.LAYOUT_HORIZONTAL, app);

		// add the icons with the same size 
		final ToolbarIcon diagramIcon0 = new ToolbarIcon(app.loadImage(imagePath+"histogramme.png"), app,workPlaceScene);
		final ToolbarIcon diagramIcon1 = new ToolbarIcon(app.loadImage(imagePath+"pie.png"), app,workPlaceScene);

		/* Must set Alignment and Layout before addChild.
		 * Because it's the addChild() function valid the alignment and the Layout
		 */
		diagramIconContainer.addChild(diagramIcon0);
		diagramIconContainer.addChild(diagramIcon1);
		diagramIconContainer.setNoStroke(true);

		/*
		 * Current container 
		 */
		currentContainer = classIconContainer;
		//		currentContainer = useCaseIconContainer;
		//		currentContainer = diagramIconContainer;

		/*
		 * Tabs list 
		 */
		tabList = new ToolbarTabArray(this.app,this,tabListWidth,tabListHeight);
		tabList.addTab(classIconContainer,"Class");
		tabList.addTab(useCaseIconContainer,"UseCase");
		tabList.addTab(diagramIconContainer,"Diagram");

		//tap the pseudo power button to show the tool bar
		this.registerInputProcessor(new TapProcessor(this.app));
		this.addGestureListener(TapProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent ge) {
				// TODO Auto-generated method stub
				TapEvent te = (TapEvent)ge;
				switch (te.getTapID()) {
				case TapEvent.TAPPED:
					if(tappable){
						if(!isOpened)
							show();
						else
							hide();
					}
					else
						tappable = true;
					break;
				default:
					break;
				}
				return false;
			}
		});

		// Combine the components

		this.addChild(tabList);

		toolBarWidth = currentContainer.getWidthXY(TransformSpace.GLOBAL)+touchableSpaceWidth;
		toolBarWidth =  toolBarWidth > minTbWidth ? toolBarWidth : minTbWidth; //min Width
		this.setSizeLocal(toolBarWidth, toolBarHeight);

		tabList.selectTabByName("Class");

		// set the tab list position
		tabList.setPositionRelativeToParent(
				new Vector3D(
						this.getCenterPointRelativeToParent().x,
						-tabList.getHeightXY(TransformSpace.LOCAL)/2-2
						)
				);

		// disable rotate and scale gestures
		this.removeAllGestureEventListeners(RotateProcessor.class); 
		this.removeAllGestureEventListeners(ScaleProcessor.class);
//		this.removeAllGestureEventListeners(DragProcessor.class);

		this.setPositionRelativeToParent(new Vector3D(app.width/2,app.height-toolBarHeight/2));
		//		this.hide();

		/*
		 * radial menu
		 */

		final IMTInputEventListener saveFileListener = new IMTInputEventListener() {
			@Override
			public boolean processInputEvent(final MTInputEvent inEvt) {
				// Most input events in MT4j are an instance of AbstractCursorInputEvt (mouse, multi-touch..)
				if (inEvt instanceof MTFingerInputEvt) {
					final MTFingerInputEvt cursorInputEvt = (MTFingerInputEvt) inEvt;
					switch (cursorInputEvt.getId()) {
					case TapEvent.GESTURE_ENDED:
						System.out.println("saving file");
						try
						{
							FileOutputStream fileOut = new FileOutputStream("test.sat");
							ObjectOutputStream out = new ObjectOutputStream(fileOut);
							out.writeObject(instance);
							out.close();
							fileOut.close();
						}catch(IOException i)
						{
							i.printStackTrace();
						}
						break;
					default:
						break;
					}
				} else {
					System.out.println("Some other event occured:" + inEvt);
				}

				return false;
			}
		};

		final IMTInputEventListener quitListener = new IMTInputEventListener() {
			@Override
			public boolean processInputEvent(final MTInputEvent inEvt) {
				// Most input events in MT4j are an instance of AbstractCursorInputEvt (mouse, multi-touch..)
				if (inEvt instanceof MTFingerInputEvt) {
					final MTFingerInputEvt cursorInputEvt = (MTFingerInputEvt) inEvt;
					switch (cursorInputEvt.getId()) {
					case TapEvent.GESTURE_ENDED:
						System.out.println("Quit");
						System.exit(0);
						break;
					default:
						break;
					}
				} else {
					System.out.println("Some other event occured:" + inEvt);
				}

				return false;
			}
		};

		this.registerInputProcessor(new TapAndHoldProcessor(mtApplication, 1000));
		this.addGestureListener(TapAndHoldProcessor.class, new TapAndHoldVisualizer(mtApplication, this));
		this.addGestureListener(TapAndHoldProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent ge) {
				TapAndHoldEvent e = (TapAndHoldEvent)ge;
				if (e.getId() == TapAndHoldEvent.GESTURE_ENDED && e.isHoldComplete()){

					tappable = false;
					final List<MTMenuItem> menuItems = new ArrayList<MTMenuItem>();
					final MTMenuItem menu1 = new MTMenuItem("File", null);

					menu1.addSubMenuItem(new MTMenuItem("Open", null));

					final MTMenuItem subMenu11 = new MTMenuItem("Save", null);
					subMenu11.addInputEventListener(saveFileListener);
					menu1.addSubMenuItem(subMenu11);

					final MTMenuItem subMenu12 = new MTMenuItem("Save as", null);
					//subMenu12.addInputEventListener(rotateInputListener);
					menu1.addSubMenuItem(subMenu12);

					final MTMenuItem menu2 = new MTMenuItem("Undo", null);
					final MTMenuItem menu3 = new MTMenuItem("Redo", null);
					final MTMenuItem menu4 = new MTMenuItem("Hide", null);
					final MTMenuItem menu5 = new MTMenuItem("Quit", null);
					menu5.addInputEventListener(quitListener);

					menuItems.add(menu1);
					menuItems.add(menu2);
					menuItems.add(menu3);
					menuItems.add(menu4);
					menuItems.add(menu5);

					// Create menu
					final Vector3D vector = new Vector3D(e.getCursor().getCurrentEvtPosX(), e.getCursor().getCurrentEvtPosY());

					final IFont font = FontManager.getInstance().createFont(mtApplication, "arial.ttf",
							16, // Font size
							new MTColor(255, 255, 255, 255), // Font fill color
							true); // Anti-alias

					MTRadialMenu mtRadialMenu = new MTRadialMenu(mtApplication, vector, font, 1f, menuItems);
					WorkPlaceScene.getInstance().getCanvas().addChild(mtRadialMenu);
				}
				return false;
			}
		});


	}
}
